package com.qys.livesMall.shop.service.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.CollectionUtils;
import com.baomidou.mybatisplus.core.toolkit.ObjectUtils;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.qys.livesMall.common.exception.QysException;
import com.qys.livesMall.common.result.R;
import com.qys.livesMall.common.utils.DateUtils;
import com.qys.livesMall.common.utils.MessageUtils;
import com.qys.livesMall.shop.dao.H2ShopBaseDao;
import com.qys.livesMall.shop.mapper.SeckillActivityMapper;
import com.qys.livesMall.shop.mapper.SeckillGoodsMapper;
import com.qys.livesMall.shop.mapper.ShopGoodsInfoMapper;
import com.qys.livesMall.shop.modal.dto.SeckillActivityAppDto;
import com.qys.livesMall.shop.modal.dto.SeckillDto;
import com.qys.livesMall.shop.modal.dto.SeckillGoodsDto;
import com.qys.livesMall.shop.modal.dto.ShopProductDto;
import com.qys.livesMall.shop.modal.entity.*;
import com.qys.livesMall.shop.modal.query.QuerySeckill;
import com.qys.livesMall.shop.modal.query.QuerySeckillActivityApp;
import com.qys.livesMall.shop.modal.query.QuerySeckillShopGoods;
import com.qys.livesMall.shop.modal.vo.*;
import com.qys.livesMall.shop.scheduledTask.DelayTaskDispatcher;
import com.qys.livesMall.shop.scheduledTask.TimeWheelRunner;
import com.qys.livesMall.shop.scheduledTask.taksEnum.TaskTypeEnum;
import com.qys.livesMall.shop.scheduledTask.task.SeckillTaks;
import com.qys.livesMall.shop.service.*;
import jakarta.annotation.Resource;
import jakarta.validation.constraints.NotNull;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.time.Duration;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 *
 * @author gmx
 * @since 2023-07-03
 */
@Service
public class SeckillActivityServiceImpl extends ServiceImpl<SeckillActivityMapper, SeckillActivity> implements SeckillActivityService {
    @Resource
    private SeckillActivityMapper seckillActivityMapper;
    @Resource
    private SeckillGoodsMapper goodsMapper;
    @Resource
    private SeckillGoodsService seckillGoodsService;
    @Resource
    private SeckillGoodsShopService seckillGoodsShopService;
    @Resource
    private H2ShopBaseService shopBaseService;

    @Resource
    private SeckillOrderService orderService;

    @Resource
    private H2ShopBaseDao h2ShopBaseDao;

    @Resource
    private ShopGoodsInfoService shopGoodsInfoService;
    @Resource
    private ShopGoodsInfoMapper shopGoodsInfoMapper;
    @Resource
    private ShopGoodsSkuService shopGoodsSkuService;
    @Resource
    private ShopGoodsSkuStocksService stocksService;
    @Resource
    private TimeWheelRunner timeWheelRunner;

    /****
     * 有效活动时间查询
     * @return
     */
    @Override
    public List<SeckillActivityAppDto> validActivity(QuerySeckillActivityApp seckillActivityApp) {
        long now = System.currentTimeMillis();
        List<SeckillActivity> salist = seckillActivityMapper.validActivity(seckillActivityApp);
        List<SeckillActivityAppDto> seckillActivityAppDtos = new ArrayList<>();
        if (ObjectUtils.isNotEmpty(salist)){
            for (SeckillActivity seckillActivity : salist) {
                SeckillActivityAppDto appDto = new SeckillActivityAppDto();
                BeanUtil.copyProperties(seckillActivity,appDto);
                appDto.setNow(now);
                seckillActivityAppDtos.add(appDto);
            }
        }
        return seckillActivityAppDtos;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public R addSeckill(SeckillDto seckillDto) {
        Date now = new Date();
        @NotNull long statTime = seckillDto.getStartTime();
        @NotNull long endTime = seckillDto.getEndTime();
        int i = Long.compare(statTime, now.getTime());
        if (i<=0){
         return R.fail(MessageUtils.message("time.error"));
        }
        i=Long.compare(statTime, endTime);
        if(i>=0){
            return R.fail(MessageUtils.message("time.error"));
        }
        SeckillActivity seckillActivity = new SeckillActivity();
        BeanUtil.copyProperties(seckillDto,seckillActivity);
        seckillActivity.setCreateTime(now.getTime());
        seckillActivity.setUpdateTime(now.getTime());
        if(!super.saveOrUpdate(seckillActivity)) throw new QysException(MessageUtils.message("system.error.seckill.activity"));
        LambdaQueryWrapper<SeckillGoods> goodsLambdaQueryWrapper = new LambdaQueryWrapper<>();
        goodsLambdaQueryWrapper.eq(SeckillGoods::getActivityId,seckillActivity.getId());
        List<SeckillGoods> seckillGoodList = seckillGoodsService.list(goodsLambdaQueryWrapper);
        if (ObjectUtils.isNotEmpty(seckillGoodList)){
            if(!seckillGoodsService.remove(goodsLambdaQueryWrapper)) throw new QysException(MessageUtils.message("system.error.seckill.goods"));
            List<Long> sgId = seckillGoodList.stream().map(SeckillGoods::getId).collect(Collectors.toList());
            LambdaQueryWrapper<SeckillGoodsShop> shopLambdaQueryWrapper =new LambdaQueryWrapper<>();
            shopLambdaQueryWrapper.in(SeckillGoodsShop::getGoodsId,sgId);
            if(!seckillGoodsShopService.remove(shopLambdaQueryWrapper)) throw new QysException(MessageUtils.message("system.error.seckill.goods"));;
        }
        for (SeckillGoodsDto seckillGood : seckillDto.getSeckillGoods()) {
            ShopGoodsSku goodsSku = shopGoodsSkuService.getGoodsSku(seckillGood.getSkuId(), Long.valueOf(seckillGood.getShopId().get(0)));
            SeckillGoods seckillGoods = new SeckillGoods();
            BeanUtil.copyProperties(seckillGood,seckillGoods);
            seckillGoods.setActivityId(seckillActivity.getId().toString());
            seckillGoods.setNum(seckillDto.getNum());
            if(goodsSku!=null){
                ShopGoodsSku shopGoodsSku = goodsSku;
                ShopGoodsInfo shopGoodsInfo = shopGoodsInfoService.getById(shopGoodsSku.getShopGoodsId());
                seckillGoods.setName(shopGoodsInfo.getGoodsName());
                seckillGoods.setInfoId(shopGoodsInfo.getGoodsId() +"");
                seckillGoods.setImages(shopGoodsInfo.getImage());
            }
            ObjectMapper objectMapper = new ObjectMapper();
            String shopIdsJson;
            try {
                shopIdsJson = objectMapper.writeValueAsString(seckillGood.getShopId());
                seckillGoods.setShopId(shopIdsJson);
                if(!seckillGoodsService.save(seckillGoods)) throw new QysException(MessageUtils.message("system.error.seckill.goods"));
            } catch (JsonProcessingException e) {
                // 处理JSON转换异常
                e.printStackTrace();
                throw new QysException(MessageUtils.message("system.error.seckill.goods"));
            }
            for (String shopId : seckillGood.getShopId()) {
                H2ShopBase base = shopBaseService.queryById(Long.valueOf(shopId));
                SeckillGoodsShop goodsShop = new SeckillGoodsShop();
                goodsShop.setActivityId(seckillActivity.getId().toString());
                goodsShop.setGoodsId(seckillGoods.getId().toString());
                goodsShop.setShopId(base.getId().toString());
                goodsShop.setShopName(base.getShopName());
                if (!seckillGoodsShopService.save(goodsShop)) throw new QysException(MessageUtils.message("system.error.seckill.goods"));
            }
        }
        if (seckillDto.getAppointment()!=0){
            long appointment = TimeUnit.MINUTES.toMillis(seckillDto.getAppointment());
            long time = statTime - appointment;
            SeckillTaks seckillTaks=new SeckillTaks();
            seckillTaks.setActivityId(seckillActivity.getId().toString());
            seckillTaks.setActivityName(seckillActivity.getActivityName());
            seckillTaks.setType(0);
            seckillTaks.setTimeout((time-System.currentTimeMillis())/1000);
            seckillTaks.setTimeUnit(TimeUnit.SECONDS);
            seckillTaks.setTaskType(TaskTypeEnum.Seckill.getTaskType());
            DelayTaskDispatcher.offerTask(seckillTaks);
        }
        return R.ok();
    }

    @Override
    public R<Page<SeckillVo>> QueryList(QuerySeckill querySeckill) {
        long now = new Date().getTime();
        Page<SeckillActivity> activityPage =Page.of(querySeckill.getCurrent(), querySeckill.getSize());
        LambdaQueryWrapper<SeckillActivity> lambdaQueryWrapper =new LambdaQueryWrapper<>();
        if (ObjectUtils.isNotEmpty(querySeckill.getShopType())){
            lambdaQueryWrapper.eq(SeckillActivity::getShopType,querySeckill.getShopType());
        }
        if(ObjectUtils.isNotEmpty(querySeckill.getName())){
            lambdaQueryWrapper.like(SeckillActivity::getActivityName,querySeckill.getName());
        }
        if (ObjectUtils.isNotEmpty(querySeckill.getStartTime())){
            lambdaQueryWrapper.ge(SeckillActivity::getStartTime,querySeckill.getStartTime());
        }
        if (ObjectUtils.isNotEmpty(querySeckill.getEndTime())){
            lambdaQueryWrapper.le(SeckillActivity::getEndTime,querySeckill.getEndTime());
        }
        if (ObjectUtils.isNotEmpty(querySeckill.getStatus())){
            if (querySeckill.getStatus().equals("1")){
                lambdaQueryWrapper.gt(SeckillActivity::getStartTime,new Date().getTime());
            }
            if (querySeckill.getStatus().equals("2")){
                lambdaQueryWrapper.lt(SeckillActivity::getStartTime,new Date().getTime());
                lambdaQueryWrapper.gt(SeckillActivity::getEndTime,new Date().getTime());
            }
            if (querySeckill.getStatus().equals("3")){
                lambdaQueryWrapper.lt(SeckillActivity::getEndTime,new Date().getTime());
            }
        }
        Page<SeckillActivity> activityPageList = super.page(activityPage, lambdaQueryWrapper);
        Page<SeckillVo> seckillVoPage = new Page<>();
        BeanUtil.copyProperties(activityPageList,seckillVoPage);
        seckillVoPage.setRecords(new ArrayList<SeckillVo>());
        for (SeckillActivity record : activityPageList.getRecords()) {
            String status = "";
            int i = Long.compare(record.getStartTime(), now);
            if (i>0){
                status="1";
            }
            if (i<=0){
                int g = Long.compare(record.getEndTime(), now);
                if (g<0){
                    status="3";
                }else {
                    status="2";
                }
            }
            SeckillVo seckillVo = new SeckillVo();
            seckillVo.setId(record.getId());
            seckillVo.setName(record.getActivityName());
            seckillVo.setStartTime(record.getStartTime());
            seckillVo.setEndTime(record.getEndTime());
            seckillVo.setCreateTime(record.getCreateTime());
            seckillVo.setDescription(record.getDescription());
            seckillVo.setShopType(record.getShopType().toString());
            seckillVo.setOrderMoneys(BigDecimal.ZERO);
            seckillVo.setUserNum("0");
            seckillVo.setStatus(status);
            List<SeckillOrder> order = orderService.queryByActivitId(record.getId());
            int num = order.size();
            seckillVo.setOrderNum(String.valueOf(num));
            if (ObjectUtils.isNotEmpty(order)){
                order.stream().forEach(e->{
                    BigDecimal money = seckillVo.getOrderMoneys();
                    seckillVo.setOrderMoneys(money.add(e.getMoney()));
                });
                int userNum = order.stream().collect(Collectors.groupingBy(SeckillOrder::getUserId)).size();
                seckillVo.setUserNum(String.valueOf(userNum));
            }
            seckillVoPage.getRecords().add(seckillVo);
        }
        return R.ok(seckillVoPage);
    }

    @Override
    public R<Page<ShopProductDto>> goodsList(QuerySeckillShopGoods seckillShopGoods) {
        LambdaQueryWrapper<H2ShopBase> baseLambdaQueryWrapper = new LambdaQueryWrapper<>();
        if(!seckillShopGoods.getType().equals("0")){
            baseLambdaQueryWrapper.eq(H2ShopBase::getType,seckillShopGoods.getType());
        }
        baseLambdaQueryWrapper.eq(H2ShopBase::getStatus,"0");
        List<H2ShopBase> shopBaseList = h2ShopBaseDao.list(baseLambdaQueryWrapper);
        Page<ShopGoodsInfo> page = Page.of(seckillShopGoods.getCurrent(),seckillShopGoods.getSize() );
        List<Long> shopId = shopBaseList.stream().map(H2ShopBase::getId).collect(Collectors.toList());
        if(CollectionUtils.isNotEmpty(shopId)){
            LambdaQueryWrapper<ShopGoodsInfo> goodsInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            goodsInfoLambdaQueryWrapper.eq(ShopGoodsInfo::isStatus,true);
            goodsInfoLambdaQueryWrapper.eq(ShopGoodsInfo::getIsDelete,"1");
            goodsInfoLambdaQueryWrapper.in(ShopGoodsInfo::getShopId,shopId);
            if(ObjectUtils.isNotEmpty(seckillShopGoods.getGoodsName())){
                goodsInfoLambdaQueryWrapper.like(ShopGoodsInfo::getGoodsName, seckillShopGoods.getGoodsName());
            }
            goodsInfoLambdaQueryWrapper.groupBy(ShopGoodsInfo::getGoodsId).
                    groupBy(ShopGoodsInfo::getShopId);
            page = shopGoodsInfoService.page(page, goodsInfoLambdaQueryWrapper);
        }
        Page<ShopProductDto> productPage = new Page<>();
        BeanUtil.copyProperties(page,productPage);
        if (ObjectUtils.isEmpty(page.getRecords())){
            return R.ok(productPage);
        }
        productPage.setRecords(new ArrayList<ShopProductDto>());
        if (ObjectUtils.isEmpty(page.getRecords()))return R.ok(productPage);
        for (ShopGoodsInfo record : page.getRecords()) {
            boolean jump = false;
            ShopProductDto product = new ShopProductDto();
            LambdaQueryWrapper<ShopGoodsSku> skuLambdaQueryWrapper = new LambdaQueryWrapper<>();
            skuLambdaQueryWrapper.eq(ShopGoodsSku::getShopGoodsId,record.getId());
            List<ShopGoodsSku> sku = shopGoodsSkuService.list(skuLambdaQueryWrapper);
            for (ShopGoodsSku shopGoodsSku : sku) {
                shopGoodsSku.setGoodsName(record.getGoodsName());
                ShopGoodsSkuStocks stocks = stocksService.queryBySkuId(shopGoodsSku.getId());
                if (ObjectUtils.isEmpty(stocks)){
                 jump=true;
                 continue;
                }
                shopGoodsSku.setPrice(stocks.getPrice());
            }
            if (jump){
                continue;
            }
            BeanUtil.copyProperties(record,product);
            product.setGoodsSkus(sku);
            productPage.getRecords().add(product);
            LambdaQueryWrapper<ShopGoodsInfo> shopGoodsInfoLambdaQueryWrapper = new LambdaQueryWrapper<>();
            shopGoodsInfoLambdaQueryWrapper.eq(ShopGoodsInfo::getGoodsId,record.getGoodsId());
            List<ShopGoodsInfo> shopGoods = shopGoodsInfoService.list(shopGoodsInfoLambdaQueryWrapper);
            List<Long> shopIds = shopGoods.stream().map(ShopGoodsInfo::getShopId).collect(Collectors.toList());
            List<H2ShopBase> shopBases = h2ShopBaseDao.listByIds(shopIds);
            product.setShopList(shopBases);
        }
        return R.ok(productPage);
    }

    @Override
    public R<Page<ShopGoodsSkuVO>> listSearchGoods(QuerySeckillShopGoods seckillShopGoods) {
        Page<ShopGoodsSkuVO> page = new Page<>(seckillShopGoods.getCurrent(),seckillShopGoods.getSize());
        return R.ok(shopGoodsInfoMapper.listSearchGoods(page,seckillShopGoods));
    }

    @Override
    public R<List<ShopGoodsSkuVO>> getSkuList(Long goodsId) {
        return R.ok(shopGoodsInfoMapper.getSkuList(goodsId));
    }

    public List<H2ShopBase> getShopList(Long skuId){
        List<Long> shopIdList = seckillGoodsService.getShopList(skuId);
        if (shopIdList.size()>0){
            return h2ShopBaseDao.listByIds(shopIdList);
        }else {
            return null;
        }
    }

    @Override
    public List<SeckillGoods> getGoods(Long activityId) {
        LambdaQueryWrapper<SeckillGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SeckillGoods::getActivityId,activityId);
        List<SeckillGoods> seckillGoods = seckillGoodsService.list(queryWrapper);

        return seckillGoods;
    }

    @Override
    public List<String> makeJson(String json) {
        ObjectMapper objectMapper = new ObjectMapper();

        try {
            // 将JSON字符串转换为Java对象
            List<String> shopIds = objectMapper.readValue(json, new TypeReference<List<String>>(){});
            return shopIds;
            // 现在你可以使用shopIds变量，它是一个List<String>类型的对象
            // 进行你需要的操作
            // ...
        } catch (JsonProcessingException e) {
            // 处理JSON转换异常
            e.printStackTrace();
        }
        return null;
    }

    @Override
    public List<SeckillActivity> getByGoodsId(Long goodsId, Long shopId) {
        return seckillActivityMapper.getByGoodsId(goodsId,shopId);
    }

    @Override
    public SeckillActivityAppVO getSeckillInfo(Long activityId) {
        SeckillActivity seckillActivity =getById(activityId);
        if (null==seckillActivity){
            return null;
        }
        SeckillActivityAppVO seckillActivityAppVO=new SeckillActivityAppVO();
        BeanUtil.copyProperties(seckillActivity,seckillActivityAppVO);

        LambdaQueryWrapper<SeckillGoods> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.eq(SeckillGoods::getActivityId,activityId);
        queryWrapper.orderByAsc(SeckillGoods::getSort);
        List<SeckillGoods> seckillGoods = seckillGoodsService.list(queryWrapper);
        if (CollectionUtils.isNotEmpty(seckillGoods)){
            List<SeckillGoodsAppVO> list=new ArrayList<>();
            for (SeckillGoods goods:seckillGoods){
                SeckillGoodsAppVO seckillGoodsAppVO=new SeckillGoodsAppVO();
                BeanUtil.copyProperties(goods,seckillGoodsAppVO);
                list.add(seckillGoodsAppVO);
            }
            seckillActivityAppVO.setSeckillGoodsAppVOS(list);
        }

        return seckillActivityAppVO;
    }


}
